var game = new Object();

// Stop jQuery from using cached data
$.ajaxSetup({ cache: false });

// Some variables
game.loadStage = 0;
game.hdRatio = 1;
game.tick = 0;
game.scenes = {
    current: 0,
    loading: 0,
    main: 1
}
game.timestamp = new Date().getTime();
game.playerEntity;

game.fps = new Object();
game.fps.calc = 0;
game.fps.frame = 0;
game.fps.time = 0;

// Error logging
game.ajaxError = function(value) {
    return function(jqxhr, settings, exception) {
        var errTxt = 'Failed to load "' + value + '": ' + jqxhr.status + ' (' + jqxhr.statusText + ')';
        if (exception instanceof SyntaxError) { 
            errTxt += '\n   ' + exception.message;
        }
        console.log(errTxt);
    };
};

// Load libraries
game.loadLibs = function(next) {
    $.each(game.libs, function(index, value) {
        $.getScript(value, function(data) {
            console.log('Loaded "' + value + '"');
            game.loadedLibs++;
        })
        .fail(function(value) {
            return game.ajaxError(value);
        }(value));
    });
};
game.libs = [
    'js/lib/jcanvas.min.js',
    'js/lib/class.js',
    'js/sprite.js',
    'js/sprites.js',
    'js/map.js',
    'js/entity.js',
    'js/input.js'
];
game.loadedLibs = 0;

// Calculate how loaded we are
game.loadedPercent = function() {
    // Calculate individuals
    var pcts = [
        game.loadedLibs / game.libs.length,
        typeof sprites == 'undefined' ? 0 : sprites.loaded / sprites.count,
        typeof sprites == 'undefined' ? 0 : sprites.loadedImg / sprites.count,
        typeof map == 'undefined' ? 0 : map.loaded / map.count
    ];
    
    // Calculate total
    var total = 0;
    for (var i = 0; i < pcts.length; i++) {
        total += pcts[i];
    }
    
    // Return total / count
    return (total / pcts.length) * 100;
}

// Sets up and begins animation frames
game.start = function() {
    // Set loading flags
    game.scenes.current = game.scenes.loading;
    game.loadStage = 0;
    
    // Modify elements based on screen size
    game.calculateScreenDimensions();
    
    // Begin loading necessary libraries
    game.loadLibs()
    
    // Bind events
    $(window).resize(game.calculateScreenDimensions);
    
    // Prepare animation using browser optimizations
    var animFrame = window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            window.oRequestAnimationFrame      ||
            window.msRequestAnimationFrame     ||
            null ;
            
    if (animFrame !== null) {
        var recursiveAnim = function() {
            game.update();
            animFrame(recursiveAnim);
        };

        // start the mainloop
        animFrame(recursiveAnim);
    } else {
        // This is messy, but it's your fault for your shitty browser 
        setInterval(game.update, 1000.0 / 60.0); // Hope for 60 fps
    }
};

// Recalculate screen dimensions and scale
game.calculateScreenDimensions = function() {
    // Calculate maximum dimensions for 16:9 aspect ratio using
    // current window size
    var sWidth = $(window).width();
    var sHeight = $(window).height();
    if (sWidth > sHeight * (16 / 9)) {
        // Window is landscape (good!)
        var nWidth = sHeight * (16 / 9);
        var nHeight = sHeight;
    } else {
        // This is for portrait - it *shouldn't* ever be called.
        var nWidth = sWidth;
        var nHeight = sWidth * (9 / 16);
    }
    // Round to the nearest pixel
    nWidth = Math.round(nWidth);
    nHeight = Math.round(nHeight);
    // Modify game canvases to fill the space
    $('.scene_main').css({
        "padding-left": (sWidth - nWidth) / 2,
        "padding-top": (sHeight - nHeight) / 2,
    })
    $('canvas.game').css({
        width: nWidth,
        height: nHeight
    });
    // Set the hdRatio variable with the new ratio (used to 
    // calculate image sizes)
    game.hdRatio = nWidth / 1920;
    console.log("Set dimensions: " + nWidth + "x" + nHeight 
        + " (" + (Math.round(100 * game.hdRatio) / 100) + ")");
}

// Scene transition
game.transitionScene = function(newScene) {
    game.scenes.current = newScene;
}

// Loading screen update
game.updateScene_loading = function() {
    // Do things based on the loading stage
    switch (game.loadStage) {
        // JS libraries
        case 0: 
            // Set loading status
            $('.loadingstatus').text('Loading libraries');
            // Ensure libraries are loaded first
            if (game.loadedLibs == game.libs.length) {
                // Setup event handlers
                $(document).on('mousemove', game.queueEvent);
                $(document).on('mousedown', game.queueEvent);
                $(document).on('keydown', game.queueEvent);
                $(document).on('keyup', game.queueEvent);
                // Begin loading resources
                map.load();
                sprites.load();
                sprite.initJCanvas();
                // Advance load stage
                console.log("Done loading libraries");
                game.loadStage++;
            }
            break;
        // Sprites
        case 1: 
            // Set loading status
            $('.loadingstatus').text('Loading sprite data');
            // Ensure sprite data is loaded
            if (sprites.loaded == sprites.count) {
                // Begin loading images associated with sprites
                sprites.loadImages();
                // Advance load stage
                console.log("Done loading sprite data");
                game.loadStage++;
            }
            break;
        // Maps
        case 2: 
            // Set loading status
            $('.loadingstatus').text('Loading map data');
            // Ensure sprite data is loaded
            if (map.loaded == map.count) {
                // Advance load stage
                console.log("Done loading map data");
                game.loadStage++;
            }
            break;
        // Sprite images
        case 3: 
            // Set loading status
            $('.loadingstatus').text('Loading sprite images');
            // Ensure sprite images are loaded
            if (sprites.loadedImg == sprites.count) {
                // Advance load stage
                console.log("Done loading sprite images");
                game.loadStage++;
            }
            break;
        // Cleanup
        case 4: 
            // Set loading text to 'loaded', status text to blank,
            // and loading bar to full
            $('.loadingtext').text('Loaded');
            $('.loadingbar div').css('width', '100%');
            $('.loadingstatus').text('');
            // Done loading
            console.log("Done loading after " + (new Date().getTime() - game.timestamp) + "ms");
            map.set('editor_test');
            game.transitionScene(game.scenes.main);
            // Create some test entities (DEBUG)
            for (var i = 0; i < 0; i++) {
                var n = Math.floor(Math.random()*2)+1;
                //console.log("Sprite " + n);
                new EntityTestAI('player_boy' + n).setPos(5, 5);
            }
            break;
    }
    // Animate the "loading..." text and progress bar (4/sec)
    if (game.tick % 15 == 0) {
        // Text
        var loadDot = $('.loadingtext span');
        loadDot.text(loadDot.text().length == 3 ? '' : loadDot.text() + '.')
        // Bar
        $('.loadingbar div').css('width', game.loadedPercent() + '%');
    }
}

// Main screen update
game.updateScene_main = function() {
    map.draw();
    entities.update();
    // Calculate FPS
    if (game.fps.frame++ >= 60) {
        var curTime = new Date().getTime();
        game.fps.calc = Math.floor(game.fps.frame / (curTime - game.fps.time) * 100000) / 100;
        game.fps.time = curTime;
        game.fps.frame = 0;
    }
    // Draw FPS
    $fgCanvas.drawText({
        fillStyle: "#000000",
        //strokeStyle: "#000000",
        //strokeWidth: 1,
        align: "start",
        x: 443, y: 20,
        fontSize: "20pt",
        fontFamily: "BitLight", //'Arial Black, Gadget, sans-serif',
        text: Math.floor(game.fps.calc)
    })
}

// 'Mainloop' function
game.update = function() {
    game.parseEvents();
    switch (game.scenes.current) {
        case game.scenes.loading:
            game.updateScene_loading();
            break;
        case game.scenes.main:
            game.updateScene_main();
            break;
    }
    game.tick++;
};

// Event stack
game.queue = new Array();

// Event handler
game.parseEvents = function() {
    // Create a copy of the queue for this frame and wipe
    var frameQueue = game.queue.slice(0);
    game.queue = new Array();
    
    // Loop the events
    //for (var i = 0; i < frameQueue.length; i++) {
    while (e = frameQueue.shift()) {
        switch (e.type) {
            case 'mousedown':
                i_mouse.down(e);
                break;

            case 'mousemove':
                i_mouse.move(e);
                break;
            
            case 'keydown':
                keyboard.keyDown(e);
                break;
            
            case 'keyup':
                keyboard.keyUp(e);
                break;
        }
    }
};

// Add events to the queue
game.queueEvent = function(e) {
    game.queue.push(e);
};

// Go
$(document).ready(function() {
    // Set jQuery shortcuts
    $bgCanvas = $('canvas.background').first();
    $enCanvas = $('canvas.entities').first();
    $fgCanvas = $('canvas.foreground').first();
    
    // Set context shortcuts
    $bgCanvasCtx = $bgCanvas.get(0).getContext('2d');
    $enCanvasCtx = $enCanvas.get(0).getContext('2d');
    $fgCanvasCtx = $fgCanvas.get(0).getContext('2d');

    game.start();
});